package com.changgou.search.service.impl;
import com.alibaba.fastjson.JSON;
import com.changgou.entity.Result;
import com.changgou.feign.SkuFeign;
import com.changgou.search.service.SkuSearchService;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SkuSearchServiceImpl implements SkuSearchService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Override
    public void importSkuList(List<Map> skuList) {

        //1.创建批处理对象
        BulkRequest bulkRequest=new BulkRequest(  );
        //2.构建批处理对象
        for(Map sku:skuList){
            IndexRequest indexRequest=new IndexRequest( "sku" );
            indexRequest.id( String.valueOf(sku.get( "id" )  )  );
            Map spec = JSON.parseObject( String.valueOf( sku.get( "spec" ) ), Map.class );
            sku.put( "spec",spec );
            indexRequest.source( sku );
            bulkRequest.add( indexRequest );
        }
        //3.执行批量处理

        try {
            BulkResponse bulkResponse = restHighLevelClient.bulk( bulkRequest, RequestOptions.DEFAULT );
            System.out.println("执行批量处理结果："+bulkResponse.status().getStatus());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Autowired
    private SkuFeign skuFeign;

    @Override
    public void importSkuListBySpuId(String spuId) {
        Result skuResult =  skuFeign.findSkuListBySpuId( spuId );
        if(skuResult.isFlag()){
            List<Map> skuList=  (List<Map>)skuResult.getData();
            if(skuList!=null){
                importSkuList( skuList );
            }
        }else{
            System.out.println("远程调用失败");
        }

    }

    @Override
    public void deleteSkuListBySpuId(String spuId) {

        DeleteByQueryRequest deleteByQueryRequest=new DeleteByQueryRequest( "sku" );
        TermQueryBuilder termQuery= QueryBuilders.termQuery( "spuId",spuId );
        deleteByQueryRequest.setQuery( termQuery );
        try {
            restHighLevelClient.deleteByQuery(deleteByQueryRequest,RequestOptions.DEFAULT  );
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    @Override
    public void importAll() {

        //分页查询sku
        Map map=new HashMap(  );
        map.put( "status","1" );
        map.put( "isDelete","0" );

        int pageNo=1;

        while(true){
            System.out.println("正在导入第"+pageNo+"页数据");
            Result result = skuFeign.findPage( map, pageNo, 1000 );
            //{total:100,rows:[]}
            List<Map> skuList= (List<Map>)((Map)result.getData()).get( "rows" );
            if(skuList.size()==0){
                break;
            }
            importSkuList( skuList );
            pageNo++;
        }

    }


    @Autowired
    private RedisTemplate redisTemplate;

    private final String brandKey="BRAND_LIST";
    private final String specKey="SPEC_LIST";

    /**
     *   商品查询
     * @param searchMap
     *          keywords 查询关键字
     *          category 商品分类
     *          brand 品牌
     *          spec.*  规格
     *          price 价格 0-500
     *          pageNo 页码
     *          pageSize 每页记录数
     *          sort 排序字段
     *          sortOrder 排序规则（升序或降序）
     * @return
     *          rows 商品查询结果
     *          categoryList  商品分类列表
     *          brandList  品牌列表
     *          specList 规格列表  [ { name:'规格名称'，options:[ "规格选项","规格选项" ]  }  ]
    */
    @Override
    public Map search(Map<String, String> searchMap) {
        //DSL
        //1.封装查询请求
        SearchRequest searchRequest=new SearchRequest(  );
        SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder(  );

        //1.1 条件查询 query
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //1.1.1 关键字查询
        if(searchMap.get( "keywords" )!=null){
            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery( "name", searchMap.get( "keywords" ) );
            boolQueryBuilder.must( matchQueryBuilder );
        }

        //1.1.2 商品分类过滤
        if( searchMap.get( "category" )!=null){
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery( "categoryName", searchMap.get( "category" ) );
            boolQueryBuilder.filter(termQueryBuilder  );
        }

        //1.1.3 品牌过滤
        if( searchMap.get( "brand" )!=null){
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery( "brandName", searchMap.get( "brand" ) );
            boolQueryBuilder.filter(termQueryBuilder  );
        }

        //1.1.4 规格过滤
        for( String key: searchMap.keySet() ){
            if(key.startsWith( "spec." )){
                TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery( key+".keyword", searchMap.get(key) );
                boolQueryBuilder.filter(termQueryBuilder  );
            }
        }

        //1.1.5 价格过滤
        if( searchMap.get( "price" )!=null){
            String[] price = searchMap.get( "price" ).split( "-" );//1000-1500
            if( !"0".equals(price[0]) ){
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery( "price" ).gte( price[0] + "00" );
                boolQueryBuilder.filter( rangeQueryBuilder );
            }
            if( !"*".equals(price[1]) ){
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery( "price" ).lte( price[1] + "00" );
                boolQueryBuilder.filter( rangeQueryBuilder );
            }
        }

        searchSourceBuilder.query( boolQueryBuilder );

        //1.2 高亮查询
        HighlightBuilder highlightBuilder=new HighlightBuilder(  );
        highlightBuilder.field( "name" ).preTags( "<font style='color:red'>" ).postTags( "</font>" );
        searchSourceBuilder.highlighter( highlightBuilder );

        //1.3 分组查询(聚合查询)
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms( "sku_category" ).field( "categoryName" );;
        searchSourceBuilder.aggregation( termsAggregationBuilder );

        //1.4 分页查询
        if(searchMap.get( "pageNo" )==null){
            searchMap.put( "pageNo","1" );
        }
        if(searchMap.get( "pageSize" )==null){
            searchMap.put( "pageSize","30" );
        }

        Integer pageNo = Integer.valueOf( searchMap.get( "pageNo" ) ); //页码
        Integer pageSize = Integer.valueOf( searchMap.get( "pageSize" ) ); //页大小
        int fromIndex= (pageNo-1)*pageSize;
        searchSourceBuilder.from( fromIndex );
        searchSourceBuilder.size( pageSize );

        //1.5 排序
        if(searchMap.get( "sort" )==null){
            searchMap.put( "sort","" );
        }
        if(searchMap.get( "sortOrder" )==null){
            searchMap.put( "sortOrder","DESC" );
        }
        if(!"".equals( searchMap.get( "sort" ) )){
            searchSourceBuilder.sort( searchMap.get( "sort" ),  SortOrder.valueOf( searchMap.get( "sortOrder" )   ) );
        }

        searchRequest.source( searchSourceBuilder );

        //2.封装查询结果
        Map resultMap=new HashMap(  );
        try {
            SearchResponse searchResponse = restHighLevelClient.search( searchRequest, RequestOptions.DEFAULT );

            SearchHits searchHits = searchResponse.getHits();


            //2.1 商品列表
            SearchHit[] hits = searchHits.getHits();
            List<Map> skuList=new ArrayList<>(  );
            for(SearchHit hit:hits){
                Map<String, Object> skuMap = hit.getSourceAsMap();
                if(searchMap.get( "keywords" )!=null){//处理高亮
                    Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                    HighlightField name = highlightFields.get( "name" );
                    Text[] fragments = name.fragments();
                    skuMap.put( "name", fragments[0].toString());
                }
                skuList.add( skuMap );
            }
            resultMap.put( "rows",skuList );

            //2.2 商品分类列表
            Aggregations aggregations = searchResponse.getAggregations();
            Map<String, Aggregation> aggrMap =  aggregations.getAsMap();
            Terms terms = (Terms)aggrMap.get( "sku_category" );
            List<? extends Terms.Bucket> buckets = terms.getBuckets();
            List<String> categoryList=new ArrayList<>(  );  //分类列表
            for(Terms.Bucket bucket:buckets){
                categoryList.add( bucket.getKeyAsString() ) ;
            }
            resultMap.put( "categoryList",categoryList );

            //2.3 品牌和规格列表查询
            String categoryName="";
            if(categoryList.size()>0){
                categoryName=categoryList.get( 0 );
            }
            //2.3.1 品牌列表查询
            List<Map> brandList=  (List<Map>)redisTemplate.boundHashOps(  brandKey ).get(categoryName  );
            if(brandList!=null){
                resultMap.put( "brandList",brandList );
            }else{
                resultMap.put( "brandList",new ArrayList<>( ) );
            }
            //2.3.2 规格列表查询
            List<Map> specList = (List<Map>)redisTemplate.boundHashOps( specKey ).get( categoryName );
            if(specList!=null){
                resultMap.put( "specList",specList );
            }else{
                resultMap.put( "specList",new ArrayList<>(  ) );
            }

            //2.4 页码计算

            TotalHits totalHits = searchHits.getTotalHits();
            System.out.println("记录数："+totalHits.value);
            //计算总页数
            long totalPages = (totalHits.value%pageSize==0)?(totalHits.value/pageSize):(totalHits.value/pageSize+1);
            resultMap.put( "totalPages",totalPages );

        } catch (IOException e) {
            e.printStackTrace();
        }
        return resultMap;
    }

}
